/****************************************************************************
 * Copyright (C) 2025 Chenyz. All rights reserved.
 *
 * @file    TinyOS_Semaphore.c
 *
 * @par     dependencies
 *          - TinyOS_Semaphore.h (Semaphore management definitions)
 *          - TinyOS_Event.h (Event management definitions)
 *          - TinyOS_Task.h (Task management definitions)
 *          - TinyOS_Objects.h (Core data structures)
 *
 * @author  Chenyz
 *
 * @brief   Semaphore management module for TinyOS with following features:
 *          - Counting semaphore implementation with configurable limits
 *          - Task blocking and waking on semaphore operations
 *          - Timeout support for semaphore acquisition
 *          - Non-blocking semaphore acquisition option
 *          - Priority inheritance through task scheduling
 *          - Critical section protection for thread-safe operations
 *          - Semaphore information retrieval and deinitialization
 *          - Integration with event and task management systems
 *          - Cross-platform compatibility (bare-metal/RTOS systems)
 *
 * @version V1.0
 * @date    2025-05-23
 *
 * @note    Coding standard:
 *          - 4 spaces per indent level
 *          - Follow MISRA-C 2012 guidelines
 *          - Compiler compatibility: C99 and above
 *
 ****************************************************************************/

#include "TinyOS_Semaphore.h"
#include "TinyOS_Event.h"
#include "TinyOS_Task.h"
#include "TinyOS_Objects.h"

# if TINYOS_ENABLE_SEMAPHORE == 1
/**
 * @brief Initializes a semaphore with specified parameters
 * 
 * This function sets up a semaphore control block with the specified initial
 * count and maximum count values. The semaphore is integrated with the event
 * system for task synchronization.
 * 
 * @param Semaphore Pointer to the semaphore structure to be initialized
 * @param StartCount Initial value of the semaphore counter
 * @param MaxCount Maximum allowed value for the semaphore counter (0 = no limit)
 */
void TinyOS_SemaphoreInit(
    TinyOS_SemaphoreType* Semaphore,
    uint32_t StartCount,
    uint32_t MaxCount
)
{
    /* Initialize the event block for semaphore operations */
    TinyOS_EventBlockInit(&Semaphore->EventBlock, TinyOS_EventTypeSemaphore);
    Semaphore->SemMaxCount = MaxCount;
    
    /* Set initial semaphore count based on maximum count constraint */
    if(Semaphore->SemMaxCount == 0)
    {
        /* No maximum limit - use the provided start count */
        Semaphore->SemCount = StartCount;
    }
    else
    {
        /* Apply maximum count constraint */
        if(StartCount > MaxCount)
        {
            Semaphore->SemCount = MaxCount;
        }
        else
        {
            Semaphore->SemCount = StartCount;
        }
    }
}

/**
 * @brief Attempts to acquire a semaphore with optional timeout
 * 
 * This function attempts to decrement the semaphore counter. If the counter
 * is greater than zero, it is decremented and the function returns immediately.
 * If the counter is zero, the task will block until the semaphore is available
 * or the specified timeout expires.
 * 
 * @param Semaphore Pointer to the semaphore structure
 * @param WaitTicks Maximum time to wait for semaphore (0 = no waiting)
 * @return uint32_t Error code indicating operation result
 */
uint32_t TinyOS_SemaphoreTake(
    TinyOS_SemaphoreType* Semaphore,
    uint32_t WaitTicks
)
{
    uint32_t Stauts = TinyOS_TaskEnterCritical();      
    
    /* Check if semaphore is available */
    if(Semaphore->SemCount > 0)
    {
        /* Semaphore available - decrement count and return success */
        Semaphore->SemCount--;
            
        TinyOS_TaskExitCritical(Stauts);  
        return TinyOS_ErrorType_NoError;
    }
    else
    {
        /* Semaphore not available - put task into waiting state */
        TinyOS_EventWait(
            &(Semaphore->EventBlock), 
            CurrentTask, 
            (void*)0,
            TinyOS_EventTypeSemaphore,
            WaitTicks
        );
        TinyOS_TaskExitCritical(Stauts);  
            
        /* Schedule another task while waiting */
        TinyOS_TaskScheduler();       
        return CurrentTask->TaskEventWaitResult;           
    }
}

/**
 * @brief Attempts to acquire a semaphore without blocking
 * 
 * This function attempts to decrement the semaphore counter without blocking
 * the calling task. If the semaphore is available, it is acquired immediately.
 * If not, the function returns an error without waiting.
 * 
 * @param Semaphore Pointer to the semaphore structure
 * @return uint32_t Error code indicating operation result
 */
uint32_t TinyOS_SemaphoreTakeNoWait(TinyOS_SemaphoreType* Semaphore)
{
    uint32_t Stauts = TinyOS_TaskEnterCritical();      
    
    /* Check if semaphore is available */
    if(Semaphore->SemCount > 0)
    {
        /* Semaphore available - decrement count and return success */
        Semaphore->SemCount--;
            
        TinyOS_TaskExitCritical(Stauts);  
        return TinyOS_ErrorType_NoError;
    }
    else
    { 
        /* Semaphore not available - return error without blocking */
        TinyOS_TaskExitCritical(Stauts);  
        return TinyOS_ErrorType_SourceUnavailable;        
    }
}

/**
 * @brief Releases a semaphore, potentially waking a waiting task
 * 
 * This function increments the semaphore counter. If tasks are waiting for
 * the semaphore, the highest priority task is woken instead of incrementing
 * the counter. If no tasks are waiting, the counter is incremented with
 * appropriate bounds checking.
 * 
 * @param Semaphore Pointer to the semaphore structure
 */
void TinyOS_SemaphoreGive(TinyOS_SemaphoreType* Semaphore)
{
    uint32_t Stauts = TinyOS_TaskEnterCritical(); 
    
    /* Check if any tasks are waiting for this semaphore */
    if(TinyOS_EventWaitCount(&(Semaphore->EventBlock)) > 0)
    {
        /* Wake the highest priority waiting task */
        TinyOS_TaskType* TempTaskHandler = TinyOS_EventWake(
            &(Semaphore->EventBlock),
            (void*)0,
            TinyOS_ErrorType_NoError 
        );     
        
        /* Schedule immediately if woken task has higher priority */
        if(TempTaskHandler->TaskPrioity > CurrentTask->TaskPrioity)
        {
            TinyOS_TaskScheduler();
        }
    }
    else
    {
        /* No tasks waiting - increment semaphore count */
        Semaphore->SemCount++;
        
        /* Handle counter overflow */
        if(Semaphore->SemCount == 0)
        {
            Semaphore->SemCount = 0xFFFFFFFF;
        }
        
        /* Apply maximum count constraint if specified */
        if((Semaphore->SemMaxCount) != 0 && 
            (Semaphore->SemCount > Semaphore->SemMaxCount)
        )
        {
            Semaphore->SemCount = Semaphore->SemMaxCount;
        }     
    }
    TinyOS_TaskExitCritical(Stauts); 
}

/**
 * @brief Retrieves information about a semaphore
 * 
 * This function returns the current state of the semaphore including its
 * current count, maximum count, and number of tasks waiting for it.
 * 
 * @param Semaphore Pointer to the semaphore structure
 * @param Info Pointer to a structure where the semaphore information will be stored
 */
void TinyOS_SemaphoreGetInfo(
    TinyOS_SemaphoreType* Semaphore,
    TinyOS_SemaphoreInfo* Info
)
{
    uint32_t Stauts = TinyOS_TaskEnterCritical(); 
    
    /* Copy semaphore state information */
    Info->SemCount = Semaphore->SemCount;
    Info->SemMaxCount = Semaphore->SemMaxCount;
    Info->TaskCount = TinyOS_EventWaitCount(&(Semaphore->EventBlock));
  
    TinyOS_TaskExitCritical(Stauts);     
}

/**
 * @brief Deinitializes a semaphore and wakes all waiting tasks
 * 
 * This function removes a semaphore from the system, waking up all tasks
 * that were waiting on it with a deletion error code. The semaphore count
 * is reset to zero.
 * 
 * @param Semaphore Pointer to the semaphore structure to be deinitialized
 * @return uint32_t Number of tasks that were waiting on the semaphore
 */
uint32_t TinyOS_SemaphoreDeInit(TinyOS_SemaphoreType* Semaphore)
{
    uint32_t Stauts = TinyOS_TaskEnterCritical(); 

    /* Wake all tasks waiting on this semaphore with deletion error */
    uint32_t TaskCount = TinyOS_EventRemoveAll(
        (&Semaphore->EventBlock),
        (void*)0,
        TinyOS_ErrorType_Delete 
    );        
    
    /* Reset semaphore count */
    Semaphore->SemCount = 0;
    
    TinyOS_TaskExitCritical(Stauts); 

    /* Schedule tasks if any were woken */
    if(TaskCount > 0)
    {
        TinyOS_TaskScheduler();
    }
  
    return TaskCount;    
}

#endif
